package b649a01.poperators;

import java.nio.ByteBuffer;
import java.util.Hashtable;
import java.util.StringTokenizer;

import b649a01.runners.sim_p;

/***
 * Integer store calculator.
 * 
 * @author Chao Sun
 * @version 1.0
 */
public class store extends calculator {
	private int s1;
	private int s2;
	private String register;
	private int offset;

	/**
	 * Constructor.
	 */
	public store(sim_p sim, int i, int j, String op) {
		super(sim, i, j, op);
		Hashtable<String, Integer> cycleHash = simulator.getcycleHash();
		this.cycleNum = cycleHash.get(op);
		busyComUnit = "ADD";
	}

	/**
	 * Set locks to registers. Set computing unit lock.
	 * 
	 * @param opTokenizer
	 *          the string tokenizer containing all the operands
	 */
	@Override
	public void fetchRegs(StringTokenizer opTokenizer) {
		// add computing unit lock
		comUnitProperty.put("unit", busyComUnit);
		comUnitProperty.put("pipeIndex", pipelineIndex);
		simulator.addbusyComUnits(this, comUnitProperty);
		// get s1 register name and index
		source1 = opTokenizer.nextToken();
		s1Index = Integer.parseInt(source1.substring(1));
		readRegs.add(source1);
		// get s2 memory offset
		source2 = opTokenizer.nextToken();
		StringTokenizer sTokenizer = new StringTokenizer(source2, "(");
		offset = Integer.parseInt(sTokenizer.nextToken());
		register = sTokenizer.nextToken();
		if (!register.startsWith("R")) {
			System.err.println("Address must be stored in an integer register");
			System.exit(1);
		}
		readRegs.add(register);
		readRegProperty.put("vector", readRegs);
		readRegProperty.put("pipeIndex", pipelineIndex);
		simulator.aadreadRegs(this, readRegProperty);
	}

	/**
	 * Assign values to register unless there is RAW hazard. Remove read locks.
	 */
	@Override
	public void assignRegs() {
		R = simulator.getR();
		s1 = R[s1Index];
		int registerNum = Integer.parseInt(register.substring(1,
				register.length() - 1));
		s2Index = R[registerNum] + offset;
		writeMemOffs.add(s2Index);
		writeMemProperty.put("vector", writeMemOffs);
		writeMemProperty.put("pipeIndex", pipelineIndex);
		simulator.addwriteMemOffs(this, writeMemProperty);
		simulator.removereadRegs(readRegProperty);
		readRegs.clear();
	}

	/**
	 * Execute an arithmetic instruction. Remove computing unit lock.
	 */
	@Override
	public void execute() {
		if (!finishFlag) {
			s2 = s1;
			finishFlag = true;
		}

		cycleNum--;
	}

	/**
	 * Write results back to memory or complete a branch.
	 */
	public void memory() {
		ByteBuffer buffer = ByteBuffer.allocate(4);
		buffer.putInt(s2);
		byte buf[] = buffer.array();
		for (int i = 0; i < 4; i++) {
			simulator.memdumpArray(buf[i], s2Index + i);
		}
		simulator.removewriteMemOffs(writeMemProperty);
		writeMemOffs.clear();
		aliveFlag = false;
	}

}